using System;
using System.Collections.Generic;
using SCG.SolarVengeanceEngine;
using SCG.General;

namespace SCG.SolarVengeance.Scenarios
{
    public class FleetBattle : Scenario
    {
        #region Initializations

        private ScenarioParameter enbBH;
        private ScenarioParameter enbPL;
        private ScenarioParameter enbWH;
        private List<StarShip> vShip = new List<StarShip>();
        private Dictionary<Player, int> oShip = new Dictionary<Player, int>();
        private List<Wormhole> vWormHole = new List<Wormhole>();
        private List<BlackHole> vBlackHole = new List<BlackHole>();
        private List<Pulsar> vPulsar = new List<Pulsar>();
        private Dictionary<SCGPoint, bool> vPoint = new Dictionary<SCGPoint, bool>();
        private Random doublernd = new Random();

        public FleetBattle()
        {

            enbBH = CreateParameter("Black Holes Enabled?", 1, 0, 1);
            enbPL = CreateParameter("Pulsars Enabled?", 1, 0, 1);
            enbWH = CreateParameter("Worm Holes Enabled?", 1, 0, 1);

        }

        public override bool UsesCapitals
        {
            get
            {
                return false;
            }
        }

        public override PlayModeRecommendation Recommendation
        {
            get
            {
                return PlayModeRecommendation.MultiPlayer;
            }
        }

        public override string Description
        {
            get
            {
                return "The last Star Lord standing after 1000 impulses will be crowned the victor.  Enabling Black holes is not suggested for the faint of heart.";

            }
        }
        public override string Author
        {
            get
            {
                return "Ugly Green Things";
            }
        }
        public override int MaxPlayers
        {
            get
            {
                return 8;
            }
        }

        //don't assign capitals
        public override bool AssignCapitals
        {
            get
            {
                return false;
            }
        }
        #endregion

        public override void BuildScenario(int numPlayers, int capitalValues, int startingResources)
        {
            #region Scenario Initializations

            //clear previously assigned dictionaries
            vShip.Clear();
            oShip.Clear();

            //Determine fleet values for each player, they all share equal strengths
            int commandRange = Random(8, 13);
            int scanRange = Random(9, 15);
            int bs = Random(30, 50);
            int stRange = Random(8, 13);
            int spyRange = Random(5, 9);

            //Assign fleet locations of each player, make sure they are not too close to each other, and outside nebula
            List<SCGPoint> pts = new List<SCGPoint>();
            foreach (Player p in Game.Players)
            {
                SCGPoint testPoint = new SCGPoint();
                bool pointOK = false;
                oShip.Add(p, 0);
                do
                {
                    //get a random point about 40 spaces away from center
                    testPoint.X = Random(0, 99);
                    testPoint.Y = Random(0, 99);
                    double dist = Distance(testPoint.X, testPoint.Y, 50, 50);
                    if (dist > 35 && dist < 45)
                    {
                        pointOK = true;

                        //must also be at least 6 away from all other players
                        foreach (SCGPoint ptTest in pts)
                            if (Distance(testPoint.X, testPoint.Y, ptTest.X, ptTest.Y) < 6)
                            {
                                pointOK = false;
                                break;
                            }
                    }
                }
                while (!pointOK);

            #endregion

                #region Create StarFleets

                //this is the fleet location!
                pts.Add(testPoint);
                oShip[p] = 0;

                //center Battlestation at this location
                int x = (int)testPoint.X;
                int y = (int)testPoint.Y;
                CreateStarShip(x, y, p, StarShipType.BattleStation, 6, bs, false);
                
                //create scanship below it
                CreateStarShip(x, y + 1, p, StarShipType.ScanShip, 20, scanRange, false);

                //create Drones
                for (int d = 0; d < 8; d++)
                    CreateStarShip(x - 4 + d, y + 4, p, StarShipType.Drone, 12, 0, false);

                //create W3 scouts
                for (int scout = 0; scout < 8; scout++)
                    CreateStarShip(x - 4, y - 4 + scout, p, StarShipType.WarShip, 14, 3, false);

                //create W4 battery
                for (int w4 = 0; w4 < 6; w4++)
                    CreateStarShip(x - 3, y - 3 + w4, p, StarShipType.WarShip, 12, 4, false);

                //create W6 battery & Elites
                for (int w6 = 0; w6 < 2; w6++)
                {
                    CreateStarShip(x - 2, y - 1 - w6, p, StarShipType.WarShip, 10, 6, false);
                    CreateStarShip(x - 2, y + 1 + w6, p, StarShipType.Elite, 20, 5, false);
                }


                //create SpyShip
                CreateStarShip(x, y - 2, p, StarShipType.SpyShip, 15, spyRange, false);

                //create CommandShip
                CreateStarShip(x, y - 1, p, StarShipType.CommandShip, 20, commandRange, false);

                //create StarTillery
                for (int st = 0; st < 2; st++)
                    CreateStarShip(x + 2, y - st, p, StarShipType.StarTillery, 20, stRange, false);

                //create cloaked groups
                for (int c = 0; c < 4; c++)
                    CreateStarShip(x - 1 + c, y - 4, p, StarShipType.WarShip, 15, 7, true);
            }
                #endregion

            #region Create Map

            //Create Random Nebula
            int numNebula = SVGame.RNG.Next(4) + 2;
            while (numNebula > 0)
            {
                CreateNebula(SVGame.RNG.Next(40) + 30, SVGame.RNG.Next(40) + 30, SVGame.RNG.Next(5) + 4, SVGame.RNG.Next(40) + 30);
                numNebula--;
            }
            //Create Random Wormholes
            int numWormholes = SVGame.RNG.Next(4) + 1;
            while (numWormholes > 0 && enbWH.Value == 1)
            {
                CreateWormhole(SVGame.RNG.Next(100), SVGame.RNG.Next(100), SVGame.RNG.Next(40) + 30, SVGame.RNG.Next(40) + 30);
                numWormholes--;
            }
            numWormholes = SVGame.RNG.Next(4) + 1;
            while (numWormholes > 0 && enbWH.Value == 1)
            {
                CreateWormhole(SVGame.RNG.Next(40) + 30, SVGame.RNG.Next(40) + 30, SVGame.RNG.Next(100), SVGame.RNG.Next(100));
                numWormholes--;
            }
            //Create Random Pulsars within the cluster
            int pulsars = Random(numPlayers, (numPlayers + 3));
            while (pulsars > 0 && enbPL.Value == 1)
            {
                SCGPoint ptPulsar = new SCGPoint();
                ptPulsar = new SCGPoint(Random(25, 75), Random(25, 75));
                CreatePulsar((int)ptPulsar.X, (int)ptPulsar.Y);
                pulsars--;
            }

            //Create Black Holes just outside the cluster perimeter
            int BlackHolesCreated = 0;
            Dictionary<int, int> BHInfoXpos = new Dictionary<int, int>();
            Dictionary<int, int> BHInfoYpos = new Dictionary<int, int>();
            int bhX = 0;
            int bhY = 0;
            int BlackHoles = Random(numPlayers, (numPlayers + 10));
            while (BlackHoles > 0 && enbBH.Value == 1)
            {
                bool BlackHolesOK = false;
                SCGPoint ptBlackHoles = new SCGPoint();
                do
                {
                    ptBlackHoles = new SCGPoint(Random(10, 90), Random(10, 90));
                    double dist = Distance(ptBlackHoles.X, ptBlackHoles.Y, 50, 50);
                    BlackHolesOK = dist > 45;
                    if (BlackHolesOK == true)
                    {
                        if (BlackHolesCreated > 0)
                        {
                            for (int d = 0; d < BlackHolesCreated; d++)
                            {
                                bhX = BHInfoXpos[d];
                                bhY = BHInfoYpos[d];
                                double bhdist = Distance(ptBlackHoles.X, ptBlackHoles.Y, bhX, bhY);
                                if (bhdist < 5)
                                    BlackHolesOK = false;
                            }
                        }
                    }
                }
                while (!BlackHolesOK);
                CreateBlackHole((int)ptBlackHoles.X, (int)ptBlackHoles.Y, Random(10, 15));
                BHInfoXpos.Add(BlackHolesCreated, (int)ptBlackHoles.X);
                BHInfoYpos.Add(BlackHolesCreated, (int)ptBlackHoles.Y);
                BlackHolesCreated++;
                BlackHoles--;
            }

            #endregion

        }

        #region Process Player Information and Victory Conditions

        public override void ProcessImpulse(int impulse)
        {
            if (impulse == 1)
            {
                DynamicEvents.DisplayMessage("This scenario has a 1000 impulse time limit.  You cannot hide to win this level.");
            }

            Player vp = null;
            int numplayers = Game.Players.Count;
            int highestcount = 0;

            #region Count Starships

            foreach (Player p in Game.Players)
            {
                oShip[p] = 0;
                foreach (StarShip s in Game.StarShips)
                {
                    if (s.Owner == p)
                    {
                        if ((s.ShipType == StarShipType.WarShip) | (s.ShipType == StarShipType.DoppleShip) | (s.ShipType == StarShipType.Elite) | (s.ShipType == StarShipType.BattleStation))
                        {
                            oShip[p]++;
                        }
                    }
                }
                #endregion

                #region Early Elimination

                if (oShip[p] == 0)
                    p.Eliminated = true;
                else
                    p.Eliminated = false;

                #endregion
            }

            #region Normal Victory

            if (impulse >= 100)
            {
                foreach (Player p in Game.Players)
                {
                    if (oShip[p] == 0)
                        numplayers--;
                    else
                        vp = p;
                }
                if (numplayers == 1)
                {
                    vp.Victor = true;
                }
            }

            #endregion

            #region Time-Out Victory

            if (impulse >= 1000)
            {
                foreach (Player p in Game.Players)
                {
                    if (oShip[p] > highestcount)
                    {
                        if (vp != null) vp.Eliminated = true; //eliminate the player that has a lower war count
                        vp = p; //substitute the new player into highest war count
                        highestcount = oShip[p];
                    }
                    else if (oShip[p] == highestcount)
                    {
                        if (vp != null) vp.Eliminated = true; //eliminate the player that has a lower war count
                        vp = null;
                        p.Eliminated = true;
                    }
                    else
                    {
                        p.Eliminated = true;
                    }
                }
                if (vp != null)
                {
                    vp.Victor = true; //Declare the highest war count winner
                }
                else  //Both players are eliminated if any other condition exists after 1000 impulses
                    foreach (Player p in Game.Players)
                        p.Eliminated = true;
            }

            #endregion
        }

        #endregion

    }
}




